using System;
using System.Collections;
using System.Collections.Generic;
using Nirvana.Common;
using UnityEngine;

namespace Nirvana
{
    /// <summary>
    /// 用Resources模仿AssetBundle加载（瞎写的）
    /// </summary>
    public class ResourcesMgr : MonoBehaviour
    {
        #region 简易单例

        public static ResourcesMgr Instance
        {
            get
            {
                if (_instance == null)
                {
                    if (!Application.isPlaying)
                    {
                        Debug.LogError("不能创建非运行时实例");
                        return null;
                    }

                    Create();
                }

                return _instance;
            }
        }

        private static ResourcesMgr _instance;

        private static void Create()
        {
            if (_instance == null)
            {
                GameObject root = GameObject.Find("MonoSingleton");
                if (root == null)
                {
                    root = new GameObject("MonoSingleton");
                }

                DontDestroyOnLoad(root);
                _instance = root.AddComponent<ResourcesMgr>();
            }
        }

        #endregion

        /// <summary>
        /// 单个资源的加载器
        /// </summary>
        public class RequestHandler : IPoolObject
        {
            private ResourceRequest _request;
            private Action<RequestHandler> _callback;
            private bool _isLoaded;
            private object asset;

            public RequestHandler()
            {
                _isLoaded = false;
            }

            public void SetAssetPath(string path)
            {
                _request = Resources.LoadAsync(path);
            }

            public void SetRequestCallback(Action<RequestHandler> callback)
            {
                _callback = callback;
            }

            public void Update()
            {
                if (!_isLoaded && _request != null && _request.isDone)
                {
                    _isLoaded = true;
                    asset = _request.asset;
                    _callback?.Invoke(this);
                }
            }

            public bool IsLoaded()
            {
                return _isLoaded;
            }

            public object GetAsset()
            {
                if (IsLoaded())
                {
                    return asset;
                }

                return null;
            }

            public void OnGet() { }
            public void OnRelease() { }
        }

        private List<RequestHandler> _updateHandlers = new List<RequestHandler>();
        private Dictionary<string, RequestHandler> _handlers = new Dictionary<string, RequestHandler>();

        private void Update()
        {
            var removeIdx = new List<int>();
            for (int i = 0; i < _updateHandlers.Count; i++)
            {
                _updateHandlers[i].Update();
                if (_updateHandlers[i].IsLoaded())
                {
                    removeIdx.Add(i);
                }
            }

            for (int i = removeIdx.Count - 1; i >= 0; --i)
            {
                _updateHandlers.RemoveAt(removeIdx[i]);
            }

            removeIdx.Clear();
        }

        public RequestHandler Get(string path, Action<RequestHandler> callback)
        {
            if (!_handlers.TryGetValue(path, out RequestHandler handler))
            {
                // 可接对象池
                handler = ObjectPool<RequestHandler>.Get();
                handler.SetAssetPath(path);
                handler.SetRequestCallback(callback);
                _handlers.Add(path, handler);
                _updateHandlers.Add(handler);
            }

            return handler;
        }
    }
}